using System.Numerics;

namespace ProjectEuler.Core.Helpers
{
    public class Fraction
    {
        public BigInteger Numerator { get; private set; }
        public BigInteger Denominator { get; private set; }
        public long NumeratorLong { get { return long.Parse(Numerator.ToString()); } }
        public long DenominatorLong { get { return long.Parse(Denominator.ToString()); } }

        public Fraction(int numerator, int denominator)
        {
            Numerator = numerator;
            Denominator = denominator;
        }
        public Fraction(BigInteger numerator, BigInteger denominator)
        {
            Numerator = numerator;
            Denominator = denominator;
        }

        public void Simplify()
        {
            var gcd = MathHelper.GCD(Numerator, Denominator);
            Numerator = Numerator/gcd;
            Denominator = Denominator/gcd;
        }
        public Fraction Simplified()
        {
            var gcd = MathHelper.GCD(Numerator, Denominator);
            return new Fraction(Numerator/gcd, Denominator/gcd);
        }

        public void Reciprocate()
        {
            var swap = Numerator;
            Numerator = Denominator;
            Denominator = swap;
        }
        
        public void AddTo(BigInteger wholeNumber)
        {
            Numerator += wholeNumber * Denominator;
        }

        public static bool AreEquivalent(Fraction f1, Fraction f2)
        {
            var f1simplified = f1.Simplified();
            var f2simplified = f2.Simplified();

            return (f1simplified.Numerator == f2simplified.Numerator) &&
                   (f1simplified.Denominator == f2simplified.Denominator);
        }

        public void AddTo(Fraction f)
        {
            // a/b + c/d = (ad + bc) / bd
            var a = Numerator;
            var b = Denominator;
            var c = f.Numerator;
            var d = f.Denominator;
        
            Numerator = (a*d) + (b*c);
            Denominator = b*d;
        
            Reduce();
        }
        
        private void Reduce()
        {
            var gcd = MathHelper.GCD(Numerator, Denominator);
            Numerator = Numerator/gcd;
            Denominator = Denominator/gcd;
        }
    }
}